package com.atguigu.tingshu.payment.service.impl;

import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.util.PayUtil;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.user.UserInfoVo;

import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;

import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Autowired
    private WxPayV3Config wxPayV3Config;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;


    @Override
    public Map<String, Object> createJsapi(String paymentType, String orderNo) {
        Map<String, Object> map = null;
        try {
            Long userId = AuthContextHolder.getUserId();
            PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(paymentType, orderNo, userId);
            // 1.构建config对象
            RSAAutoCertificateConfig config = wxPayV3Config.getConfig();
            // 2.构建service 利用config对象
            JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
            // 3.调用预支付下单接口方法
            // 4.构建请求参数
            PrepayRequest request = new PrepayRequest();
            Amount amount = new Amount();
            amount.setTotal(1); // 1分钱 测试用 任何商品实际付款都是1分钱
            request.setAmount(amount);
            request.setAppid(wxPayV3Config.getAppid());
            request.setMchid(wxPayV3Config.getMerchantId());
            request.setDescription(paymentInfo.getContent());
            request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
            request.setOutTradeNo(orderNo); // 给微信平台的订单编号
            Payer payer = new Payer();
            Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfo(userId);
            UserInfoVo userInfoVoData = userInfoVoResult.getData();
            Assert.notNull(userInfoVoData, "远程调用用户微服务获取用户信息使用openid失败");
            String wxOpenId = userInfoVoData.getWxOpenId();
            payer.setOpenid(wxOpenId); // 付款者的openid
            request.setPayer(payer);
            // 发起请求
            PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
            // 解析数据
            String packageVal = response.getPackageVal(); // 获取会话标识
            String paySign = response.getPaySign(); // 签名
            String nonceStr = response.getNonceStr(); // 随机字符串
            String signType = response.getSignType(); // RSA 且仅支持 RSA
            String timeStamp = response.getTimeStamp(); // 时间戳
            // 返回前端
            map = new HashMap<>();
            map.put("nonceStr", nonceStr);
            map.put("timeStamp", timeStamp);
            map.put("package", packageVal);
            map.put("signType", signType);
            map.put("paySign", paySign);
        } catch (Exception e) {
            log.error("微信下单异常:{}", e.getMessage());
            throw new GuiguException(201, "微信下单异常");
        }

        return map;
    }

    @Override
    public Result<Boolean> queryPayStatus(String orderNo) {
        RSAAutoCertificateConfig config = wxPayV3Config.getConfig();
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(wxPayV3Config.getMerchantId());
        queryRequest.setOutTradeNo(orderNo);
        try {
            Transaction transaction = paymentInfoService.queryOrderByOutTradeNo(queryRequest, orderNo);
            if (null != transaction && transaction.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
                //更改订单状态
                paymentInfoService.updatePaymentStatus(transaction);
                return Result.ok(true);
            }
        } catch (ServiceException e) {
            // API返回失败, 例如ORDER_NOT_EXISTS
            System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            System.out.printf("reponse body=[%s]\n", e.getResponseBody());
        }
        return Result.ok(false);
    }

    @Override
    public void asyncNotify(HttpServletRequest request) {
        //1.回调通知的验签与解密
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String signature = request.getHeader("Wechatpay-Signature");
        String requestBody = PayUtil.readData(request);
        //2.构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .body(requestBody)
                .build();
        //3.初始化 NotificationParser
        NotificationParser parser = new NotificationParser(wxPayV3Config.getConfig());
        //4.以支付通知回调为例，验签、解密并转换成 Transaction
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        if (null != transaction && transaction.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
            //5.处理支付业务
            paymentInfoService.updatePaymentStatus(transaction);
        }
    }

    @Override
    public Map<String, Object> createNative(String paymentType, String orderNo, Long userId) {
//        return null;
        try {
            //保存支付记录
            PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(paymentType, orderNo, userId);
            RSAAutoCertificateConfig config = wxPayV3Config.getConfig();
            // 构建service
            com.wechat.pay.java.service.payments.nativepay.NativePayService service = new com.wechat.pay.java.service.payments.nativepay.NativePayService.Builder().config(config).build();
            com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest request = new com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest();
            request.setAppid(wxPayV3Config.getAppid());
            request.setMchid(wxPayV3Config.getMerchantId());
            request.setDescription(paymentInfo.getContent());
            request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
            request.setOutTradeNo(orderNo);
            com.wechat.pay.java.service.payments.nativepay.model.Amount amount = new com.wechat.pay.java.service.payments.nativepay.model.Amount();
            amount.setTotal(1);
            request.setAmount(amount);
            com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse response = service.prepay(request);
            // request.setXxx(val)设置所需参数，具体参数可见Request定义
//            com.wechat.pay.java.service.partnerpayments.nativepay.model.PrepayRequest prepayRequest = new com.wechat.pay.java.service.partnerpayments.nativepay.model.PrepayRequest();
//            com.wechat.pay.java.service.partnerpayments.nativepay.model.PrepayRequest request = new com.wechat.pay.java.service.partnerpayments.nativepay.model.PrepayRequest();
//            com.wechat.pay.java.service.partnerpayments.nativepay.model.Amount amount = new com.wechat.pay.java.service.partnerpayments.nativepay.model.Amount();
//            amount.setTotal(1);
//            request.setAmount(amount);
//            request.setAppid(wxPayV3Config.getAppid());
//            request.setMchid(wxPayV3Config.getMerchantId());
//            request.setSpAppid(wxPayV3Config.getAppid());
//            request.setSpMchid(wxPayV3Config.getMerchantId());
//            request.setSubAppid("wx6d56a9063db39f63");
//            request.setSubMchid(wxPayV3Config.getMerchantId());
//            request.setDescription(paymentInfo.getContent());
//            request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
//            request.setOutTradeNo(paymentInfo.getOrderNo());
//            // 调用下单方法，得到应答
//            com.wechat.pay.java.service.partnerpayments.nativepay.model.PrepayResponse response = service.prepay(request);
            // 使用微信扫描 code_url 对应的二维码，即可体验Native支付
            System.out.println(response.getCodeUrl());

            Map result = new HashMap<>();
            result.put("codeUrl", response.getCodeUrl());
            return result;
        } catch (ServiceException e) {
            e.printStackTrace();
            throw new GuiguException(201, e.getErrorMessage());
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            throw new GuiguException(201, "订单号不存在");
        } catch (Exception e) {
            e.printStackTrace();
            throw new GuiguException(201, "微信下单异常");
        }

    }
}
